package org.autumn.review.thread;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * object structure
 * <p>
 * object head
 * hashcode lock age classPoint array length
 * object instance data
 * alignment data
 */
@Slf4j
public class MarkWord {
    static Thread t1, t2, t3;

    public static void main(String[] args) throws InterruptedException {
    }

    /**
     * batchReBiased
     *
     * @throws InterruptedException
     */
    private static void batchReBiased() throws InterruptedException {
        delay();
        ArrayList<Object> list = new ArrayList<>();
        t1 = new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                Object o = new Object();
                list.add(o);
                synchronized (o) {
                    log.info("t1 -> {}", i);
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
            }
            LockSupport.unpark(t2);
        }, "t1");
        t1.start();

        t2 = new Thread(() -> {
            LockSupport.park();
            for (int i = 0; i < list.size(); i++) {
                Object o = list.get(i);
                synchronized (o) {
                    log.info("t2 -> {}", i);
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
                log.info("t2 -> {} unlock ->", i);
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }, "t2");
        t2.start();
    }

    /**
     * batchLockCancel
     *
     * @throws InterruptedException
     */
    private static void batchLockCancel() throws InterruptedException {
        delay();
        ArrayList<Object> list = new ArrayList<>();
        t1 = new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                Object o = new Object();
                list.add(o);
                synchronized (o) {
                    log.info("t1 -> {}", i);
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
            }
            LockSupport.unpark(t2);
        }, "t1");
        t1.start();

        t2 = new Thread(() -> {
            LockSupport.park();
            for (int i = 0; i < list.size(); i++) {
                Object o = list.get(i);
                synchronized (o) {
                    log.info("t2 -> {}", i);
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
                log.info("t2 -> {} unlock ->", i);
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
            LockSupport.unpark(t3);
        }, "t2");
        t2.start();

        t3 = new Thread(() -> {
            LockSupport.park();
            for (int i = 0; i < list.size(); i++) {
                Object o = list.get(i);
                synchronized (o) {
                    log.info("t3 -> {}", i);
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
                log.info("t3 -> {} unlock ->", i);
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }, "t3");
        t3.start();

        t3.join();

        System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
    }

    /**
     * lightweight()
     *
     * @throws InterruptedException
     */
    private static void lightweight() throws InterruptedException {
        delay();
        Object o = new Object();
        t1 = new Thread(() -> {
            synchronized (o) {
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
            LockSupport.unpark(t2);
        }, "t1");
        t1.start();

        t2 = new Thread(() -> {
            LockSupport.park();
            synchronized (o) {
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }, "t2");
        t2.start();

        t2.join();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

    /**
     * test no lock and bias lock and cancel lock and lightweight lock
     *
     * @throws InterruptedException
     */
    private static void testObjectLayout() throws InterruptedException {
        Object o = new Object();

        log.info("no lock");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        log.info("bias lock");
        delay();
        Object o1 = new Object();
        System.out.println(ClassLayout.parseInstance(o1).toPrintable());
        o1.hashCode();
        log.info("call hashcode() will make lightweight invalid");
        System.out.println(ClassLayout.parseInstance(o1).toPrintable());
        synchronized (o1) {
            log.info("lightweight lock");
            System.out.println(ClassLayout.parseInstance(o1).toPrintable());
        }
        log.info("unlock");
        System.out.println(ClassLayout.parseInstance(o1).toPrintable());
    }


    /**
     * make the lightweight lock effective
     *
     * @throws InterruptedException
     */
    public static void delay() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
    }


}
